package com.duowan.realtime.scheduled.batch.writer;

import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.ItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcParameterUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author tangsicheng
 * @version 1.0
 * @since 1.0
 */
public class SimpleJdbcWriter<T> implements ItemWriter<List<T>>, InitializingBean {

    private DataSource dataSource;

    private String sql;

    private NamedParameterJdbcOperations namedParameterJdbcTemplate;

    private int parameterCount;

    private ItemSqlParameterSourceProvider itemSqlParameterSourceProvider;


    private boolean usingNamedParameters = true;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        if (namedParameterJdbcTemplate == null) {
            this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.hasText(sql, "必须制定sql");
        Assert.notNull(dataSource, "必须制定datasource");
        Assert.notNull(namedParameterJdbcTemplate, "A DataSource or a NamedParameterJdbcTemplate is required.");
        Assert.notNull(sql, "An SQL statement is required.");
        List<String> namedParameters = new ArrayList<String>();
        parameterCount = JdbcParameterUtils.countParameterPlaceholders(sql, namedParameters);
        if (namedParameters.size() > 0) {
            if (parameterCount != namedParameters.size()) {
                throw new InvalidDataAccessApiUsageException("You can't use both named parameters and classic \"?\" placeholders: " + sql);
            }
            usingNamedParameters = true;
        }
        if (!usingNamedParameters) {
            //TODO
            throw new UnsupportedOperationException("not implemented yet");
            //Assert.notNull(itemPreparedStatementSetter, "Using SQL statement with '?' placeholders requires an ItemPreparedStatementSetter");
        }
    }


    public void setSql(String sql) {
        this.sql = sql;
    }

    @Override
    public void write(List<? extends List<T>> items) throws Exception {
        List<T> itemList = merge(items);
        if (!itemList.isEmpty()) {
            int[] updateCounts = null;
            if (usingNamedParameters) {
                if (itemList.get(0) instanceof Map) {
                    updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, itemList.toArray(new Map[0]));
                } else {
                    SqlParameterSource[] batchArgs = new SqlParameterSource[itemList.size()];
                    int i = 0;
                    for (T item : itemList) {
                        batchArgs[i++] = itemSqlParameterSourceProvider.createSqlParameterSource(item);
                    }
                    updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, batchArgs);
                }
            } else {
                //TODO 增加 sql ？？？的方式
                throw new UnsupportedOperationException("not implemented yet");
            }
        }

    }

    private List<T> merge(List<? extends List<T>> lists) {
        List<T> result = new LinkedList<T>();
        for (List<T> list : lists) {
            result.addAll(list);
        }
        return result;
    }

    public void setItemSqlParameterSourceProvider(ItemSqlParameterSourceProvider itemSqlParameterSourceProvider) {
        this.itemSqlParameterSourceProvider = itemSqlParameterSourceProvider;
    }
}